package ita.class1.group2.supermarket.common.captain.manager;

import ita.class1.group2.supermarket.common.annotation.RequestMapping;
import ita.class1.group2.supermarket.common.captain.CaptainRouter;
import ita.class1.group2.supermarket.common.captain.model.Path;
import ita.class1.group2.supermarket.common.pojo.MessageResultCode;
import ita.class1.group2.supermarket.common.pojo.ResponseMessage;
import ita.class1.group2.supermarket.common.util.JsonUtil;
import org.apache.log4j.Logger;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * Used to manage mapping relationships for all controllers
 *
 * @author Burgess Li
 * @date 2018/07/19
 */
public final class ControllerManager {

    private static final Logger LOGGER = Logger.getLogger(ControllerManager.class);

    private Set<Class<?>> classes = null;
    private Map<Path, Method> controllers = null;
    private CaptainRouter captainRouter = null;

    public ControllerManager(Set<Class<?>> classes) {
        this.classes = classes;
        initializeControllers();
    }

    public void setCaptainRouter(CaptainRouter captainRouter) {
        this.captainRouter = captainRouter;
    }

    public void initializeControllers() {
        this.controllers = new HashMap<Path, Method>();
        for (Class cls: classes) {
            for (Method method: cls.getDeclaredMethods()) {
                if (method.isAnnotationPresent(RequestMapping.class)) {
                    Path path = new Path(method.getAnnotation(RequestMapping.class).value());
                    if (controllers.containsKey(path)) {
                        throw new RuntimeException("Define the Controller path repeatedly!");
                    } else {
                        controllers.put(path, method);
                    }
                    LOGGER.info("Controller Class: " + cls.getName() + ", Method: " + method.getName() + ", Path: " + path.toString());
                }
            }
        }
    }

    public Map<Path, Method> getControllers() {
        return controllers;
    }

    public void process(ServletRequest servletRequest, ServletResponse response) {
        try {
            Object result = this.captainRouter.route((HttpServletRequest) servletRequest);
            this.captainRouter.to((HttpServletResponse) response, result);
        } catch (Exception e) {
            ResponseMessage errorMessage = new ResponseMessage(null, MessageResultCode.ERROR, e.toString());
            try {
                response.getWriter().write(JsonUtil.obj2json(errorMessage));
                e.printStackTrace();
            } catch (Exception e1) {
                e1.printStackTrace();
            }
        }
    }

}
